package com.quan.aspect;

import com.quan.Enum.ResultEnum;
import com.quan.entity.Result;
import com.quan.exception.CallException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @author: xiexinquan520@163.com
 * User: XieXinQuan
 * DATE:2020/6/7
 */
@Aspect
@Component
@Slf4j
public class OpenFeignService {

    /**
     切入点描述 这个是controller包的切入点
     */
    @Pointcut("execution(public * com.quan.service..*.*(..))")
    public void serviceCutPoint(){}

    @Before("serviceCutPoint()")
    public void logBeforeController(JoinPoint joinPoint) {

        String mapperName = "";
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature){
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            Annotation[] annotations = method.getAnnotations();

            for (Annotation annotation  : annotations){
                if (!checkAnnotationIsRequestMapper(annotation)){
                    continue;
                }
                mapperName = getMapperValue(annotation);
                break;
            }
        }
        Class declaringType = signature.getDeclaringType();

        FeignClient feignClient = (FeignClient) declaringType.getAnnotation(FeignClient.class);
        String serviceName = feignClient.value();

        log.info("开始使用OpenFeign调用远程服务, 服务名：{}, 路径值：{}.", serviceName, mapperName);
    }

    @AfterReturning(returning = "returnOb", pointcut = "serviceCutPoint()")
    public void doAfterReturning(Object returnOb) {
        log.info("远程服务返回数据: {}", returnOb);
    }
    @Around("serviceCutPoint()")
    public Object Around(ProceedingJoinPoint pjp) throws Throwable {

        long startTime = System.currentTimeMillis();
        Object proceed = pjp.proceed();
        if (proceed == null){
            throw new CallException("系统繁忙");
        }
        if (proceed instanceof Result){
            Result result = (Result)proceed;
            if (!ResultEnum.Success.getKey().equals(result.getStatus())){
                throw new CallException(result.getMsg());
            }
        }
        long endTime = System.currentTimeMillis();

        log.info("远程调用耗时: {}ms.", (endTime - startTime));

        return proceed;

    }

    private String getMapperValue(Annotation annotation){
        if (!checkAnnotationIsRequestMapper(annotation)){
            return "";
        }
        if (annotation instanceof GetMapping){
            GetMapping annotation1 = (GetMapping) annotation;
            return StringUtils.join(annotation1.value());
        }else if (annotation instanceof PostMapping){
            PostMapping annotation1 = (PostMapping) annotation;
            return StringUtils.join(annotation1.value());
        }else if (annotation instanceof PutMapping){
            PutMapping annotation1 = (PutMapping) annotation;
            return StringUtils.join(annotation1.value());
        }else if (annotation instanceof DeleteMapping){
            DeleteMapping annotation1 = (DeleteMapping) annotation;
            return StringUtils.join(annotation1.value());
        }
        return "";
    }
    private boolean checkAnnotationIsRequestMapper(Annotation annotation){
        if (annotation instanceof GetMapping
            || annotation instanceof PostMapping
            || annotation instanceof PutMapping
            || annotation instanceof DeleteMapping){
            return true;
        }
        return false;
    }

}
